//package cn.liukuan.jps.redis;
//
//import cn.liukuan.jps.utils.RedisUtils;
//import cn.liukuan.jps.utils.SerializeUtils;
//import org.apache.lucene.index.IndexFileNames;
//import org.apache.lucene.store.*;
//import org.apache.lucene.util.Accountable;
//import org.apache.lucene.util.Accountables;
//
//import java.io.FileNotFoundException;
//import java.io.IOException;
//import java.io.Serializable;
//import java.nio.file.Files;
//import java.util.*;
//import java.util.concurrent.atomic.AtomicLong;
//
///**
// * Created by liukuan on 16/5/30.
// */
//public class RedisRAMDirectory extends BaseDirectory implements Accountable{
//    protected final RedisSerializableClient fileMap = RedisUtils.getRedisClient();
//    protected final AtomicLong sizeInBytes = new AtomicLong();
//
//    /** Used to generate temp file names in {@link #createTempOutput}. */
//    private final AtomicLong nextTempFileCounter = new AtomicLong();
//
//    /** Constructs an empty {@link Directory}. */
//    public RedisRAMDirectory() {
//        this(new SingleInstanceLockFactory());
//    }
//
//    /** Constructs an empty {@link Directory} with the given {@link LockFactory}. */
//    public RedisRAMDirectory(LockFactory lockFactory) {
//        super(lockFactory);
//    }
//
//    /**
//     * Creates a new <code>RAMDirectory</code> instance from a different
//     * <code>Directory</code> implementation.  This can be used to load
//     * a disk-based index into memory.
//     *
//     * <p><b>Warning:</b> This class is not intended to work with huge
//     * indexes. Everything beyond several hundred megabytes will waste
//     * resources (GC cycles), because it uses an internal buffer size
//     * of 1024 bytes, producing millions of {@code byte[1024]} arrays.
//     * This class is optimized for small memory-resident indexes.
//     * It also has bad concurrency on multithreaded environments.
//     *
//     * <p>For disk-based indexes it is recommended to use
//     * {@link MMapDirectory}, which is a high-performance directory
//     * implementation working directly on the file system cache of the
//     * operating system, so copying data to Java heap space is not useful.
//     *
//     * <p>Note that the resulting <code>RAMDirectory</code> instance is fully
//     * independent from the original <code>Directory</code> (it is a
//     * complete copy).  Any subsequent changes to the
//     * original <code>Directory</code> will not be visible in the
//     * <code>RAMDirectory</code> instance.
//     *
//     * @param dir a <code>Directory</code> value
//     * @exception IOException if an error occurs
//     */
//    public RedisRAMDirectory(FSDirectory dir, IOContext context) throws IOException {
//        this(dir, false, context);
//    }
//
//    private RedisRAMDirectory(FSDirectory dir, boolean closeDir, IOContext context) throws IOException {
//        this();
//        for (String file : dir.listAll()) {
//            if (!Files.isDirectory(dir.getDirectory().resolve(file))) {
//                copyFrom(dir, file, file, context);
//            }
//        }
//        if (closeDir) {
//            dir.close();
//        }
//    }
//
//    @Override
//    public final String[] listAll() {
//        ensureOpen();
//        // NOTE: this returns a "weakly consistent view". Unless we change Dir API, keep this,
//        // and do not synchronize or anything stronger. it's great for testing!
//        // NOTE: fileMap.keySet().toArray(new String[0]) is broken in non Sun JDKs,
//        // and the code below is resilient to map changes during the array population.
//        // NOTE: don't replace this with return names.toArray(new String[names.size()]);
//        // or some files could be null at the end of the array if files are being deleted
//        // concurrently
//        Set<String> fileNames = fileMap.keySet();
//        List<String> names = new ArrayList<String>(fileNames.size());
//        for (String name : fileNames) {
//            names.add(name);
//        }
//        String[] namesArray = names.toArray(new String[names.size()]);
//        Arrays.sort(namesArray);
//        return namesArray;
//    }
//
//    public final boolean fileNameExists(String name) {
//        ensureOpen();
//        return fileMap.containsKey(name);
//    }
//
//    /** Returns the length in bytes of a file in the directory.
//     * @throws IOException if the file does not exist
//     */
//    @Override
//    public final long fileLength(String name) throws IOException {
//        ensureOpen();
//        RedisRAMFile file = fileMap.getFile(name);
//        if (file == null) {
//            throw new FileNotFoundException(name);
//        }
//        return file.getLength();
//    }
//
//    /**
//     * Return total size in bytes of all files in this directory. This is
//     * currently quantized to RAMOutputStream.BUFFER_SIZE.
//     */
//    public final long ramBytesUsed() {
//        ensureOpen();
//        return sizeInBytes.get();
//    }
//
//    public Collection<Accountable> getChildResources() {
//        return Accountables.namedAccountables("file", fileMap);
//    }
//
//    @Override
//    public void deleteFile(String name) throws IOException {
//        ensureOpen();
//        RedisRAMFile file = fileMap.remove(name);
//        if (file != null) {
//            file.directory = null;
//            sizeInBytes.addAndGet(-file.sizeInBytes);
//        } else {
//            throw new FileNotFoundException(name);
//        }
//    }
//
//    @Override
//    public IndexOutput createOutput(String name, IOContext context) throws IOException {
//        ensureOpen();
//        RedisRAMFile file = newRedisRAMFile();
//        RedisRAMFile existing = fileMap.remove(name);
//        if (existing != null) {
//            sizeInBytes.addAndGet(-existing.sizeInBytes);
//            existing.directory = null;
//        }
//        fileMap.put(name, file);
//        return new RedisRAMOutputStream(name, file, true);
//    }
//
//    @Override
//    public IndexOutput createTempOutput(String prefix, String suffix, IOContext context) throws IOException {
//        ensureOpen();
//
//        // Make the file first...
//        RedisRAMFile file = new RedisRAMFile();
//
//        // ... then try to find a unique name for it:
//        while (true) {
//            String name = IndexFileNames.segmentFileName(prefix, suffix + "_" + Long.toString(nextTempFileCounter.getAndIncrement(), Character.MAX_RADIX), "tmp");
//            if (fileMap.putIfAbsent(name, file) == null) {
//                return new RedisRAMOutputStream(name, file, true);
//            }
//        }
//    }
//
//    /**
//     * Returns a new {@link RedisRAMFile} for storing data. This method can be
//     * overridden to return different {@link RedisRAMFile} impls, that e.g. override
//     * {@link RedisRAMFile#newBuffer(int)}.
//     */
//    protected RedisRAMFile newRedisRAMFile() {
//        return new RedisRAMFile(this);
//    }
//
//    @Override
//    public void sync(Collection<String> names) throws IOException {
//    }
//
//    @Override
//    public void renameFile(String source, String dest) throws IOException {
//        ensureOpen();
//        RedisRAMFile file = fileMap.getFile(source);
//        if (file == null) {
//            throw new FileNotFoundException(source);
//        }
//        fileMap.put(dest, file);
//        fileMap.remove(source);
//    }
//
//    /** Returns a stream reading an existing file. */
//    @Override
//    public IndexInput openInput(String name, IOContext context) throws IOException {
//        ensureOpen();
//        RedisRAMFile file = fileMap.getFile(name);
//        if (file == null) {
//            throw new FileNotFoundException(name);
//        }
//        long len = SerializeUtils.serialize(file).length;
//        file.length = len;
//        return new RedisRAMInputStream(name, file);
//    }
//
//    /** Closes the store to future operations, releasing associated memory. */
//    @Override
//    public void close() {
//        isOpen = false;
//        fileMap.clear();
//    }
//}